//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package impl

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/mongo-proxy/gen_code"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/x/mongo/driver/connstring"
)

type ConnectionApiImpl struct{}

func (s *ConnectionApiImpl) ConnectionClosePost(ctx context.Context, req gen_code.ConnectionClosePostRequest) (gen_code.ImplResponse, error) {
	if req.Token != token {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong token",
			},
		}, nil
	}
	infoItem, ok := clientMap.Load(req.Id)
	if !ok {
		return gen_code.ImplResponse{
			Code: 200,
			Body: req.Id,
		}, nil
	}
	info := infoItem.(*ClientInfo)
	client := info.client.(*mongo.Client)
	client.Disconnect(ctx)
	clientMap.Delete(req.Id)
	return gen_code.ImplResponse{
		Code: 200,
		Body: req.Id,
	}, nil

}

func (s *ConnectionApiImpl) ConnectionListPost(ctx context.Context, req gen_code.ConnectionListPostRequest) (gen_code.ImplResponse, error) {
	if req.Token != token {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong token",
			},
		}, nil
	}

	retList := []gen_code.ConnectionListPost200ResponseInner{}
	clientMap.Range(func(key, value any) bool {
		info := value.(*ClientInfo)
		retList = append(retList, gen_code.ConnectionListPost200ResponseInner{
			Id:    key.(string),
			Name:  info.Name,
			Hosts: info.Hosts,
		})
		return true
	})
	return gen_code.ImplResponse{
		Code: 200,
		Body: retList,
	}, nil
}

func (s *ConnectionApiImpl) ConnectionOpenPost(ctx context.Context, req gen_code.ConnectionOpenPostRequest) (gen_code.ImplResponse, error) {
	if req.Token != token {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong token",
			},
		}, nil
	}
	connCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
	defer cancel()

	cs, err := connstring.ParseAndValidate(req.MongoUrl)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}

	option := options.Client().ApplyURI(req.MongoUrl)
	client, err := mongo.Connect(connCtx, option)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	id := uuid.NewString()
	clientMap.Store(id, &ClientInfo{
		Name:     req.Name,
		Hosts:    option.Hosts,
		Database: cs.Database,
		client:   client,
	})
	return gen_code.ImplResponse{
		Code: 200,
		Body: id,
	}, nil
}
